<?php
require_once(CAKE . 'Clases/Descarga.php');
require_once(CAKE . 'Clases/PHPExcel.php');
require_once(CAKE . 'Clases/PHPExcel/Writer/Excel5.php');
require_once(CAKE . 'Clases/PHPExcel/Writer/Excel2007.php');
require_once(CAKE . 'Clases/PHPExcel/IOFactory.php');

class PhpExcelHelper extends AppHelper {

    public $xls;
    public $hoja;
    public $leer;
    protected $row = 1;
    protected $tableParams;
    protected $descargar;
    protected $imagen;

    public function __construct(View $view, $settings = array()) {
        parent::__construct($view, $settings);
    }

    /**
      Funcion Excel
      Esta funcion permite crear una hoja de calculo
      Recibe como parametro opcional
      $archivo: Direccion absoluta de un archivo tipo xls o xlxs o ods o csv para realizar su lectura
      Ejemplo:
      $this->PhpExcel->Excel();
      $this->PhpExcel->Excel($archivo);
     * */
    public function Excel($archivo = null, $config = array()) {
        $base = array('separador' => '', 'delimitador' => '');
        $config = array_merge($base, $config);
        $this->createWorksheet($archivo, $config);
    }

    /**
     * Funcion para insertar imagenes en la hoja de calculo
     * @param type $nombre: Nombre de la imagen
     * @param type $descripcion: Descripcion de la imagen
     * @param type $ruta: Ruta de la imagen
     * @param type $coordenada: Coordenadas de la imagen
     * @param type $opciones: Opciones adicionales (ancho, alto, limite columna, limite fila, redimensionar, rotacion, sombra)
     * Ejemplo:
     *      $this->PhpExcel->Imagen('Agropatria', 'Logo Agropatria', 'img/logo_agropatria.png', 'B2', array('width' => 300));
     */
    public function Imagen($nombre = 'Logo', $descripcion = 'Logo', $ruta, $coordenada = 'A1', $opciones = null) {
        $this->imagen = new PHPExcel_Worksheet_Drawing();
        $this->imagen->setName($nombre);
        $this->imagen->setDescription($descripcion);
        $this->imagen->setPath($ruta);
        $this->imagen->setCoordinates($coordenada);
        if (!empty($opciones)) {
            $base = array_merge(array(
                'height' => null,
                'width' => null,
                'offsetX' => null,
                'offsetY' => null,
                'resizeProportional' => null,
                'rotation' => null,
                'shadow' => null
                    ), $opciones);
            foreach ($base as $indice => $valor) {
                if (!empty($valor)) {
                    $atributo = 'set' . ucfirst($indice);
                    $this->imagen->$atributo($valor);
                }
            }
        }

        $this->insertarImagen();
    }

    /**
     * Funcion para insertar imagen en la hoja activa
     */
    public function insertarImagen() {
        $this->imagen->setWorksheet($this->hoja);
    }

    public function createWorksheet($archivo = null, $config) {
        $this->loadEssentials();
        $this->xls = new PHPExcel();
        $this->hoja = $this->xls->getActiveSheet();
        if (isset($archivo)) {
            $tipo = isset($config['tipo']) ? $config['tipo'] : PHPExcel_IOFactory::identify($archivo);
            $this->leer = PHPExcel_IOFactory::createReader($tipo);
            if(isset($config['separador']) && !empty($config['separador'])) {
                $this->leer->setDelimiter($config['separador']);
                $this->leer->setEnclosure($config['delimitador']);
            }
            if($tipo != 'CSV')
                $this->leer->setReadDataOnly(true);
        }
    }

    /**
      Funcion titulo reporte
      Esta funcion permite escribir el membrete al documento, recibe como parametro
      $dep: Departamento donde se Genera Reporte
      $titulo: Titulo del Reporte
      Ejemplo:
      $this->PhpExcel->titulo_reporte('departamento','titulo');
     * */
    public function titulo_reporte($dep = null, $titulo = null) {
        $this->hoja->setCellValue('A1', "AGROPATRIA - $dep");
        $this->hoja->setCellValue('A2', $titulo);
        $this->hoja->setCellValue('A3', "Fecha: " . date("d-m-Y"));
        $this->hoja->setCellValue('A4', "Hora: " . date("h:i"));
    }

    /**
     * Funcion para crear titulos dinamicos en los reportes
     * @param type $titulos: arreglo con posicion y contenido
     * Ejemplo:
     *      $titulos = array('A1' => 'TITULO REPORTE','B7'=>'wd');
     *      $this->PhpExcel->titulos_dinamicos($titulos);
     * */
    public function titulos_dinamicos($titulos) {
        foreach ($titulos as $indice => $valor)
            $this->hoja->setCellValueExplicit($indice, $valor);
    }

    /**
      Funcion titulo hoja
      Esta funcion permite escribir el nombre en la hoja de calculo, recibe como parametro
      $titulo: Titulo de la hoja
      Ejemplo:
      $this->PhpExcel->titulo_hoja('titulo');
     * */
    public function titulo_hoja($titulo = null) {
        $this->hoja->setTitle($titulo);
    }

    /**
      Funcion Configura Celda
      Esta funcion permite configura el tamaño de una celda, recibe como parametro
      $columna: Celda a configurar
      $tamanio: tamanio de la Celda
      Ejemplo:
      $this->PhpExcel->configura_celda('A1',10);
     * */
    public function configura_celda($columna = null, $tam = 10) {
        $this->hoja->getColumnDimension($columna)->setWidth($tam);
    }

    /**
      Funcion Valor Celda
      Esta funcion permite Escribir un valor en la celda, recibe como parametro
      $columna: Columna a Usar
      $fila: Fila a Usar
      $valor: array de la siguiente forma ($val,$tipo_dato,$aliniacion) donde:
      $val: Valor a mostrar en la celda
      $tipo_dato: Formato estandar de Celda ('STR','STR2','N','B','I','E')
      STR = STRING, STR2= STRING, N= NUMERIC, B= BOOLEAN, I=INLINE, E=ERROR
      $ali: Aliniacion del Texto ('L','C','R')
      Ejemplo:
      $valor=array('valor ','STR','C');
      $this->PhpExcel->valor_celda(6,1,$valor);
     * */
    public function valor_celda($columna = null, $fila = null, $valor = null) {
        if (!is_array($valor)) {
            $val = $valor;
            $cvalor = null;
            $valor[0] = $val;
        }
        if (!isset($valor[1]))
            $valor[1] = 'STR';
        if (!isset($valor[2]))
            $valor[2] = 'L';
        $oC = $this->obtener_columna($columna, $fila);
        $oR = $this->obtener_fila($columna, $fila);
        $valor[1] = trim($valor[1]); //=$this->utf8n($valor[1])
        if (strtoupper($valor[1]) == 'STR2')
            $this->hoja->getCellByColumnAndRow($columna, $fila)->setValueExplicit($valor[0], PHPExcel_Cell_DataType::TYPE_STRING2);
        else if (strtoupper($valor[1]) == 'STR')
            $this->hoja->getCellByColumnAndRow($columna, $fila)->setValueExplicit($valor[0], PHPExcel_Cell_DataType::TYPE_STRING);
        else if (strtoupper($valor[1]) == 'F')
            $this->hoja->getCellByColumnAndRow($columna, $fila)->setValueExplicit($valor[0], PHPExcel_Cell_DataType::TYPE_FORMULA);
        else if (strtoupper($valor[1]) == 'N') {
            $this->hoja->getCellByColumnAndRow($columna, $fila)->setValueExplicit($valor[0], PHPExcel_Cell_DataType::TYPE_NUMERIC);
            $this->hoja->getStyle($oC.$oR)->getNumberFormat()->setFormatCode(PHPExcel_Style_NumberFormat::FORMAT_NUMBER_COMMA_SEPARATED1);
        } else if (strtoupper($valor[1]) == 'B')
            $this->hoja->getCellByColumnAndRow($columna, $fila)->setValueExplicit($valor[0], PHPExcel_Cell_DataType::TYPE_BOOL);
        else if (strtoupper($valor[1]) == 'I')
            $this->hoja->getCellByColumnAndRow($columna, $fila)->setValueExplicit($valor[0], PHPExcel_Cell_DataType::TYPE_INLINE);
        else if (strtoupper($valor[1]) == 'E')
            $this->hoja->getCellByColumnAndRow($columna, $fila)->setValueExplicit($valor[0], PHPExcel_Cell_DataType::TYPE_ERROR);

        if (isset($valor[2])) {

            if (strtoupper($valor[2]) == 'L')
                $this->hoja->getStyle($oC . $oR)->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_LEFT);
            else if (strtoupper($valor[2]) == 'C')
                $this->hoja->getStyle($oC . $oR)->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
            else if (strtoupper($valor[2]) == 'R')
                $this->hoja->getStyle($oC . $oR)->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_RIGHT);
        }
    }

    /**
      Funcion obtener_columna
      Esta funcion permite obtener una columna, recibe como parametros
      $columna: Columna a obtener
      $fila: Fila a obtener
      Ejemplo:
      $this->PhpExcel->obtener_columna(6,1);
     * */
    public function obtener_columna($columna = null, $fila = null) {
        return $this->hoja->getCellByColumnAndRow($columna, $fila)->getColumn();
    }

    /**
      Funcion obtener_fila
      Esta funcion permite obtener una Fila, recibe como parametros
      $columna: Columna a obtener
      $fila: Fila a obtener
      Ejemplo:
      $this->PhpExcel->obtener_fila(6,1);
     * */
    public function obtener_fila($columna = null, $fila = null) {
        return $this->hoja->getCellByColumnAndRow($columna, $fila)->getRow();
    }

    public function loadWorksheet($path) {
        $this->loadEssentials();
        $this->xls = PHPExcel_IOFactory::load($path);
    }

    public function setRow($to) {
        $this->row = (int) $to;
    }

    public function setDefaultFont($name, $size) {
        $this->xls->getDefaultStyle()->getFont()->setName($name);
        $this->xls->getDefaultStyle()->getFont()->setSize($size);
    }

    /**
     * Start table
     * inserts table header and sets table params
     * Possible keys for data:
     * label - table heading
     * width - "auto" or units
     * filter - true to set excel filter for column
     * wrap - true to wrap text in column
     * Possible keys for params:
     * offset - column offset (numeric or text)
     * font - font name
     * size - font size
     * bold - true for bold text
     * italic - true for italic text
     *
     */
    public function addTableHeader($data, $params = array()) {
        $offset = 0;
        // offset
        if (array_key_exists('offset', $params))
            $offset = is_numeric($params['offset']) ? (int) $params['offset'] : PHPExcel_Cell::columnIndexFromString($params['offset']);
        // font name
        if (array_key_exists('font', $params))
            $this->xls->getActiveSheet()->getStyle($this->row)->getFont()->setName($params['font_name']);
        // font size
        if (array_key_exists('size', $params))
            $this->xls->getActiveSheet()->getStyle($this->row)->getFont()->setSize($params['font_size']);
        // bold
        if (array_key_exists('bold', $params))
            $this->xls->getActiveSheet()->getStyle($this->row)->getFont()->setBold($params['bold']);
        // italic
        if (array_key_exists('italic', $params))
            $this->xls->getActiveSheet()->getStyle($this->row)->getFont()->setItalic($params['italic']);

        // set internal params that need to be processed after data are inserted
        $this->tableParams = array(
            'header_row' => $this->row,
            'offset' => $offset,
            'row_count' => 0,
            'auto_width' => array(),
            'filter' => array(),
            'wrap' => array()
        );

        foreach ($data as $d) {
            // set label
            $this->xls->getActiveSheet()->setCellValueByColumnAndRow($offset, $this->row, $d['label']);
            // set width
            if (array_key_exists('width', $d)) {
                if ($d['width'] == 'auto')
                    $this->tableParams['auto_width'][] = $offset;
                else
                    $this->xls->getActiveSheet()->getColumnDimensionByColumn($offset)->setWidth((float) $d['width']);
            }
            // filter
            if (array_key_exists('filter', $d) && $d['filter'])
                $this->tableParams['filter'][] = $offset;
            // wrap
            if (array_key_exists('wrap', $d) && $d['wrap'])
                $this->tableParams['wrap'][] = $offset;
            $offset++;
        }
        $this->row++;
    }

    /**
     * Write array of data to actual row
     */
    public function addTableRow($data) {
        $offset = $this->tableParams['offset'];
        foreach ($data as $d) {
            $this->xls->getActiveSheet()->setCellValueByColumnAndRow($offset++, $this->row, $d);
        }
        $this->row++;
        $this->tableParams['row_count']++;
    }

    /**
     * End table
     * sets params and styles that required data to be inserted
     */
    public function addTableFooter() {
        // auto width
        foreach ($this->tableParams['auto_width'] as $col)
            $this->xls->getActiveSheet()->getColumnDimensionByColumn($col)->setAutoSize(true);
        // filter (has to be set for whole range)
        if (count($this->tableParams['filter']))
            $this->xls->getActiveSheet()->setAutoFilter(PHPExcel_Cell::stringFromColumnIndex($this->tableParams['filter'][0]) . ($this->tableParams['header_row']) . ':' . PHPExcel_Cell::stringFromColumnIndex($this->tableParams['filter'][count($this->tableParams['filter']) - 1]) . ($this->tableParams['header_row'] + $this->tableParams['row_count']));
        // wrap
        foreach ($this->tableParams['wrap'] as $col)
            $this->xls->getActiveSheet()->getStyle(PHPExcel_Cell::stringFromColumnIndex($col) . ($this->tableParams['header_row'] + 1) . ':' . PHPExcel_Cell::stringFromColumnIndex($col) . ($this->tableParams['header_row'] + $this->tableParams['row_count']))->getAlignment()->setWrapText(true);
    }

    /*     * App::import('Vendor', 'Classes/PHPExcel');
      App::import('Vendor','Classes/Writer/Excel5');
      App::import('Vendor','Classes/Writer/Excel2007');
     * Write array of data to actual row starting from column defined by offset
     * Offset can be textual or numeric representation
     */

    public function addData($data, $offset = 0) {
        // solve textual representation
        if (!is_numeric($offset))
            $offset = PHPExcel_Cell::columnIndexFromString($offset);

        foreach ($data as $d) {
            $this->xls->getActiveSheet()->setCellValueByColumnAndRow($offset++, $this->row, $d);
        }
        $this->row++;
    }

    private function extension($extension) {
        switch ($extension) {
            case 'doc':
                return 'application/msword';
                break;
            case 'docx':
                return 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
                break;
            case 'pdf':
                return 'application/pdf';
                break;
            case 'ppt':
                return 'application/vnd.ms-powerpoint';
                break;
            case 'pptx':
                return 'application/vnd.openxmlformats-officedocument.presentationml.presentation';
                break;
            case 'xls':
                return 'application/vnd.ms-excel';
                break;
            case 'xlsx':
                return 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
                break;
            case 'zip':
                return 'application/zip';
                break;
            case 'ods':
                return 'application/vnd.oasis.opendocument.spreadsheet';
                break;

            default:
                return false;
                break;
        }
    }

    /**
      Funcion mostrar
      Esta funcion permite mostrar el documento
      $filename: Nombre del archivo
      $ext: Extencion del Archivo
      $guar: Valor booleano que indica si el archivo se guardara en el servidor o si sera eliminado
      Ejemplo:
      $this->PhpExcel->mostrar('nombre_archivo','xlsx',false);
     * */
    public function mostrar($filename, $ext = 'ods', $descargar = true) {
        $file_on_server = $filename;
        $this->_View->layout = '';
        if ($ext == 'xlsx') {
            $writer_name = 'Excel2007';
        } else {
            $writer_name = 'Excel5';
        }

        $objWriter = PHPExcel_IOFactory::createWriter($this->xls, $writer_name);

        if ($descargar) {
            chdir(WWW_ROOT . 'files');
            $filename_server = md5(date("dmYhis") . rand());
            $filename_server .= '.' . $ext;
            $objWriter->save($filename_server);
            $this->descargar = new Descarga(WWW_ROOT . 'files/' . $filename_server, "$filename.$ext", $ext, $_SERVER['PHP_SELF']);
            //Quitar el true para que no elimine los archivos temporales
            $resultado = $this->descargar->download_file(false);
        } else {
            /* header('Content-Type: '.$this->extension($ext));
              header('Content-Disposition: attachment;filename="'.$filename.'.'.$ext.'"');
              header('Cache-Control: max-age=0'); */
            $objWriter->save(WWW_ROOT . "files/$filename.$ext");
            //chmod(WWW_ROOT . "files/$filename.$ext", 0777);
        }


        $this->xls->disconnectWorksheets();
    }

    /**
     * Load vendor classes
     */
    protected function loadEssentials() {
        // load vendor class

        if (!class_exists('PHPExcel')) {
            throw new CakeException('Vendor class PHPExcel not found!');
        }
    }

}
